package com.bree.erp.jsf.view;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

import org.apache.log4j.Logger;

import com.bree.erp.entity.InventoryFlow;
import com.bree.erp.entity.InventoryStatus;
import com.bree.erp.entity.PoItem;
import com.bree.erp.entity.PurchaseOrder;
import com.bree.erp.entity.Status;
import com.bree.erp.jsf.httpsess.SessionDataKey;
import com.bree.erp.jsf.httpsess.UserSessionData;
import com.bree.erp.service.InventoryFlowService;
import com.bree.erp.service.PoItemService;
import com.bree.erp.service.PurchaseOrderService;

@ManagedBean(name = "dtInventoryReceivableView")
@ViewScoped
public class InventoryReceivableView implements Serializable {

	private static final long serialVersionUID = 1L;

	private static Logger LOG = Logger.getLogger(InventoryReceivableView.class);

	@ManagedProperty(value = "#{userSession}")
	private UserSessionData userSession;

	@EJB
	private PurchaseOrderService poService;

	@EJB
	private PoItemService poItemService;

	@EJB
	private InventoryFlowService ifService;

	private PurchaseOrder purchaseOrder;
	private Map<Long, String> locationMap;
	private Map<Long, Double> partialQtyMap;
	private Map<Long, BigDecimal> actualQtyMap;

	@PostConstruct
	public void init() {

		Long id = userSession.get(SessionDataKey.SELECTED_PURCHASE_ORDER_ID,
				Long.class);
		LOG.debug("SELECTED_PURCHASE_ORDER_ID: " + id);
		if (id != null) {
			purchaseOrder = poService.read(id, true);

			if (purchaseOrder != null && purchaseOrder.getItems() != null) {
				locationMap = new HashMap<Long, String>();
				partialQtyMap = new HashMap<Long, Double>();
				actualQtyMap = new HashMap<Long, BigDecimal>();

				int count = 0;
				for (PoItem item : purchaseOrder.getItems()) {
					item.setItemNumber(++count);
					locationMap.put(item.getId(), "");
					partialQtyMap.put(item.getPartUnit().getId(), 0.0);
					actualQtyMap.put(item.getId(), BigDecimal.ZERO);
				}
				
				if(Status.PARTIAL.equals(purchaseOrder.getStatus())) {
					for(InventoryFlow inventoryFlow : purchaseOrder.getInventoryFlows()) {
						if(InventoryStatus.RECEIVED.equals(inventoryFlow.getStatus())) {
							Long partUnitId = inventoryFlow.getPartUnit().getId();
							Double partial = partialQtyMap.get(partUnitId);
							partial += inventoryFlow.getQuantity();
							
							partialQtyMap.put(partUnitId, partial);
							
						}
					}
				}
			}

		}
	}

	public String receive() {

		Long poId = purchaseOrder.getId();
		String userId = userSession.getLoggedInUser().getEmail();

		boolean forUpdate = false;
		boolean asPartial = false;
		for (Long id : locationMap.keySet()) {
			String locationBin = locationMap.get(id);
			BigDecimal actualQty = actualQtyMap.get(id);
			if (!Status.PARTIAL.equals(purchaseOrder.getStatus()) && (actualQty == null || actualQty.doubleValue() == 0.0)) {
				asPartial = true;
				continue;
			}

			forUpdate = true;

			LOG.debug("poItemId: " + id + "; Actual Qty:" + actualQty
					+ "; Bin: " + locationBin);
			PoItem poItem = poItemService.read(id);

			String warehouseId = purchaseOrder.getWarehouse().getId();
			Long partUnitId = poItem.getPartUnit().getId();
			
			double balance = poItem.getQuantity() - partialQtyMap.get(poItem.getPartUnit().getId()); 
			if(balance != actualQty.doubleValue()) {
				asPartial = true;
			}

			ifService.create(poId, warehouseId, locationBin, partUnitId,
					actualQty.doubleValue(), InventoryStatus.RECEIVED, userId);
		}

		if (forUpdate && !asPartial) {
			LOG.debug("This is transaction is complete!");
			poService.update(poId, Status.RECEIVED, userId);

			return "/inv/withdraw";
		} else {
			
			if(asPartial && forUpdate) {
				LOG.debug("This is a partial update!");
				poService.update(poId, Status.PARTIAL, userId);
			} else {
				LOG.debug("There is nothing to update!");
			}
			
			return "/inv/receive";
		}
	}

	public String release() {

		String userId = userSession.getLoggedInUser().getEmail();
		Long poId = purchaseOrder.getId();

		for (Long id : locationMap.keySet()) {
			LOG.debug("poItemId: " + id + "; Bin: " + locationMap.get(id));
			PoItem poItem = poItemService.read(id);

			String warehouseId = purchaseOrder.getWarehouse().getId();
			String locationBin = locationMap.get(id);
			Long partUnitId = poItem.getPartUnit().getId();

			ifService.create(poId, warehouseId, locationBin, partUnitId,
					poItem.getQuantity(), InventoryStatus.RELEASED, userId);
		}

		poService.update(poId, Status.CLOSED, userId);

		return "/inv/archive";
	}

	/**
	 * @return the userSession
	 */
	public UserSessionData getUserSession() {
		return userSession;
	}

	/**
	 * @param userSession
	 *            the userSession to set
	 */
	public void setUserSession(UserSessionData userSession) {
		this.userSession = userSession;
	}

	/**
	 * @return the purchaseOrder
	 */
	public PurchaseOrder getPurchaseOrder() {
		return purchaseOrder;
	}

	/**
	 * @return the locationMap
	 */
	public Map<Long, String> getLocationMap() {
		return locationMap;
	}

	/**
	 * @return the actualQtyMap
	 */
	public Map<Long, BigDecimal> getActualQtyMap() {
		return actualQtyMap;
	}

	/**
	 * @return the partialQtyMap
	 */
	public Map<Long, Double> getPartialQtyMap() {
		return partialQtyMap;
	}

}
